#include "MainRunner.h"


MainRunner::MainRunner(void)
{
}

MainRunner::~MainRunner(void)
{
}




/* INPUT accepts an initial state from the terminal, assuming it is preceded by
a problem number. 
Param: state - where to write the inputted state
*/
void MainRunner::input(int state[SIZE])
{
	scanf ("%*d");                                   /* skip over problem number */
	for (int index = 0; index < SIZE; index++)                  /* for each position */
		scanf ("%d", &state[index]);                 /* input tile in that position */
}


/* INPUT accepts an initial state from the terminal, assuming it is preceded by
a problem number. It stores it in the state vector and returns the position of
the blank tile. */
int MainRunner::inputFromFile (int s[SIZE],FILE *f)              /* state vector */
{
	int index;                                        /* index to tile positions */
	int blank;                                         /* position of blank tile */
	int tmp;
	fscanf (f,"%*d");                                   /* skip over problem number */
	for (index = 0; index < SIZE; index++)                  /* for each position */
	{
		fscanf (f,"%d", &tmp);                   /* input tile in that position */
		s[index] = tmp;
		if (s[index] == 0) blank = index;
	}      /* note blank position in passing */
	return (blank);
}

/**
 * Export the results of the algorithm run to the output file
 **/
void MainRunner::outputResults(AlgorithmInterface* algorithm,int instance, int runtime, double solutionQuality)
{
	int depth = algorithm->depth;
	double factor;
	
	if(solutionQuality==-1)
		factor = algorithm->getSolutionQualityFactor();
	else
		factor = solutionQuality;

	int numOfSolutionUpdates = algorithm->getNumOfSolutionUpdates();
	char* algorithmName = algorithm->getName();
	int closed = algorithm->closed;
	int reopened = algorithm->reopened;
	int stored = algorithm->stored;
	int expanded = algorithm->expanded;
	int generated = algorithm->generated;
	int goalUpperbound = algorithm->goalUpperbound;
	int success = (goalUpperbound>0)? ((depth<=goalUpperbound)? 1 : 0) : 1;
	double suboptimality = algorithm->desiredSuboptimality;
	// Write results to file
	FILE* output = fopen(FILENAME, "a");				/** open output file for writing **/
	
	printf ("%s\t%d\t%d\t%d\t%d\t%d\t%d\t%.2f\t%d\n",algorithmName, instance,depth, generated, expanded, runtime, goalUpperbound,factor,success);
	fprintf (output, "%s\t%d\t%d\t%d\t%d\t%d\t%d\t%.2f\t%d\n",algorithmName, instance,depth, generated, expanded, runtime, goalUpperbound,factor,success);



	fclose(output);	
}




/** 
 * Runs a single instance of an anytime search algorithm, until reaches the optimal solution or runs out of time or memory
 **/
void MainRunner::runAnytimeInstance(AlgorithmInterface* algorithm, int initialState[SIZE], int instanceCounter)
{	
	int t1,t0;					/** time measures variables **/
	double factor;				/** Solution quality **/

	printf ("Running %s on instance %d ...\n",algorithm->getName(),instanceCounter);
	algorithm->goalUpperbound=MAXG;
	t0 = clock();					  				 /** saving the start clock **/
	algorithm->run(initialState);
	t1=clock();	

	outputResults(algorithm,instanceCounter, t1-t0);
	factor = algorithm->getSolutionQualityFactor();
	while(factor!=1 && algorithm->hasMoreMemory())
	{
		algorithm->expandUntilFindGoal();
		t1 = clock();
		factor = algorithm->getSolutionQualityFactor();
		outputResults(algorithm,instanceCounter, t1-t0, factor);		
	}
	if(algorithm->hasMoreMemory()==false)
	printf("Out of memory!\n");
	algorithm->clear();
}

/**
 * Run an anytime algorithm
 **/ 
int MainRunner::anytimeRun()
{
	int instance;                                  /* number of problem instance */
	
	FILE *output;				/** output file **/	
	FILE *inputFile;			/** input file from which to read the problems */

	srand(1);                   /* initialize random number seed once at beginning */
	output = fopen(FILENAME, "wt");			/** open output file for writing **/
	fprintf(output, "Alg\t Instand\t Depth\t Generated\t Expanded\t Runtime\t GoalUB\t Subopt\t Success\t\n");
	fclose(output);										 /** closing output file **/
	inputFile = fopen(PROBLEMS_FILE,"r");


	const int NUM_OF_ALGS = 7;
	//const int ALGORITHM_CODES[] = {0,5,6,7,8,9};
	const int ALGORITHM_CODES[] = {1,2,3,4,5,6,7};
	AlgorithmInterface* algorithm;
	int algorithmCode;

	for (instance = 1; instance <= NUMBER; instance++)   /* each problem instance */
	{
		
		inputFromFile(s,inputFile); /* generate initial state */

		for(int algorithmIndex = 0;algorithmIndex<NUM_OF_ALGS;algorithmIndex++)
		{
			algorithmCode = ALGORITHM_CODES[algorithmIndex];
			switch(algorithmCode)
			{	
			case 1:
				algorithm = new AStar2D();
				break;
			case 2:
				algorithm = new AWA2D(0,1); // GBFS
				break;
			case 3:
				algorithm = new AWA2D(1,1.5); // AWA 1.1
				break;
			case 4:
				algorithm = new AWA2D(1,2.0); // AWA 1.3
				break;
			case 5:
				algorithm = new AWA2D(1,2.5); // AWA 1.5
				break;
			case 6:
				algorithm = new AWA2D(1,3.0); // AWA 1.5
				break;			
			case 7:
				algorithm = new APTS2D();
			}
			
			runAnytimeInstance(algorithm,s,instance);

			delete algorithm;
		}
	}
	fclose(inputFile);
	return 1;
}

/**
 Run the algorithm, bounded by various costs
 **/
int MainRunner::runForCost()
{
	FILE *output;				/** output file **/	
	FILE *inputFile;			/** input file from which to read the problems */
	bool success;
	srand(1);                   /* initialize random number seed once at beginning */

	output = fopen(FILENAME, "wt");			/** open output file for writing **/
	fprintf(output, "Alg\tInstance\tGoalDepth\tGenerated\tExpanded\tRuntime\tDesiredBound\tsuboptimality\tSuccess\n");	
	fclose(output);										 /** closing output file **/
	inputFile = fopen(PROBLEMS_FILE,"r");
	
	AlgorithmInterface* algorithm;
	bool solved;

	for (int instance = 1; instance <= NUMBER; instance++)   /* each problem instance */
	{
		printf(" ----------------- INSTANCE %d ---------------\n",instance);
		inputFromFile(s,inputFile); /* generate initial state */
		
		// Find optimal solution
		algorithm = new AStar2D();
		solved = runBoundedCostInstance(algorithm,s,instance,MAXG);		
		delete algorithm;

		// Run bounded cost search if A* found the optimal solution
		if (solved==false) {
			printf("Failed to solve instance %d with A*\n", instance);
			continue;
		}

		// Run a bounded cost search for each algorithm and cost bound
		for(int goalUpperbound=90;goalUpperbound>=55;goalUpperbound=goalUpperbound-5)
		{		
			printf(" ------ Running instance %d [bound %d] -- \n",instance,goalUpperbound);			
			

			// Run PTS
			algorithm = new PTS2D();
			runBoundedCostInstance(algorithm,s,instance,goalUpperbound);
			delete algorithm;
			

			// Run AWA* with different weights		
			for (double weight=1.5; weight<=3;weight=weight+0.5)
			{
				algorithm = new AWA2D(1,weight);
				runBoundedCostInstance(algorithm,s,instance,goalUpperbound);
				delete algorithm;
			}
			
		}

	
	}

	fclose(inputFile);
	return 1;
}


/**
 * Run a single instance with a given algorithm. Return true if solution equal to or less than goalUpperbound was found. 
 **/
bool MainRunner::runBoundedCostInstance(AlgorithmInterface* algorithm, int initialState[SIZE], int instanceIndex,int goalUpperbound)
{
	printf(" -- Running algorithm %s \n",algorithm->algorithmName);
	algorithm->goalUpperbound= goalUpperbound;
	int t1,t0;
	int bestGoal;
	t0 = clock();					  				 /** saving the start clock **/
	algorithm->run(initialState);
	t1=clock();			
	bestGoal = algorithm->depth;
	int success = (goalUpperbound>0)? ((bestGoal<=goalUpperbound)? 1 : 0) : 1;	
	outputResults(algorithm,instanceIndex,t1-t0);
	algorithm->clear();
	
	return ((goalUpperbound>0) && (bestGoal<=goalUpperbound));
}






